﻿namespace HZY.Framework.Core.Filters;

/// <summary>
/// Anomaly filter
/// </summary>
public class ApiExceptionFilter(ILogger<ApiExceptionFilter> logger) : IExceptionFilter, IOrderedFilter
{
    public int Order { get; set; } = int.MaxValue - 10;

    public void OnException(ExceptionContext context)
    {
        var exception = context.Exception;

        // 自定义异常
        if (exception is MessageBoxException error)
        {
            var result = error.GetResult();
            context.ExceptionHandled = true;
            context.HttpContext.Response.StatusCode = result.Code;
            context.Result = new JsonResult(error.GetResult());
            return;
        }

        if (exception is UnauthorizedAccessException)
        {
            context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            context.Result = new JsonResult(context.HttpContext.ResultUnAuth("unauthorized"));
            return;
        }

        // 封装所有异常，然后填充正确的 StatusCode
        var code = (HttpStatusCode)Enum.ToObject(typeof(HttpStatusCode),
            context.HttpContext.Response.StatusCode); // 500 if unexpected
        switch (exception)
        {
            case ArgumentException:
                code = HttpStatusCode.BadRequest; // 400
                break;
            case UnauthorizedAccessException:
                code = HttpStatusCode.Unauthorized; // 401
                break;
            case InvalidOperationException:
                code = HttpStatusCode.BadRequest; // 400
                break;
            case NotSupportedException:
                code = HttpStatusCode.NotImplemented; // 501
                break;
            case TimeoutException:
                code = HttpStatusCode.RequestTimeout; // 408
                break;
            case FileNotFoundException:
                code = HttpStatusCode.NotFound; // 404
                break;
            case DirectoryNotFoundException:
                code = HttpStatusCode.NotFound; // 404
                break;
            case KeyNotFoundException:
                code = HttpStatusCode.NotFound; // 404
                break;
            case FormatException:
                code = HttpStatusCode.BadRequest; // 400
                break;
            case OverflowException:
                code = HttpStatusCode.BadRequest; // 400
                break;
            case DivideByZeroException:
                code = HttpStatusCode.BadRequest; // 400
                break;
            case InvalidCastException:
                code = HttpStatusCode.BadRequest; // 400
                break;
            case NullReferenceException:
                code = HttpStatusCode.InternalServerError; // 500
                break;
            case StackOverflowException:
                code = HttpStatusCode.InternalServerError; // 500
                break;
            case OutOfMemoryException:
                code = HttpStatusCode.ServiceUnavailable; // 503
                break;
        }

        //nlog Writes logs to txt
        logger.LogError(exception, "error {RemoteIpAddress}",
            context.HttpContext.Connection.RemoteIpAddress?.ToString());
        context.HttpContext.Response.Headers.Append("Error", "true");
        var message = $"Server Error [ Message：{exception.Message} ]";
        var apiResult = context.HttpContext.ResultMessage(code, message);
        context.Result = new JsonResult(apiResult);
    }
}